package rpc

import (
	"fmt"
	. "leaf/core/error"
	"leaf/core/log"
	. "leaf/core/msg"
	"runtime"
)

type IServicRpc interface {
	Init()
	GetService() interface{}
	GetChannel() chan *ServiceRpcInfo
	Exec()
}

type ServiceRpcInfo struct {
	handler *RpcHandler
	msg     *PMsg
	service interface{}
	Done    chan *ServiceRpcInfo
}

type ServicRpc struct {
	service        interface{}
	rpcCallChannel chan *ServiceRpcInfo
}

func (r *ServicRpc) Init(s interface{}) {
	r.service = s
	r.rpcCallChannel = make(chan *ServiceRpcInfo, 100)
}

func (r *ServicRpc) OnClose() {

}

func (r *ServicRpc) GetChannel() chan *ServiceRpcInfo {
	return r.rpcCallChannel
}

func (r *ServicRpc) Exec(handler *RpcHandler, msg *PMsg, call bool) *ServiceRpcInfo {
	srpc := new(ServiceRpcInfo)
	srpc.handler = handler
	srpc.service = r.service
	srpc.msg = msg
	srpc.Done = make(chan *ServiceRpcInfo, 1)
	r.rpcCallChannel <- srpc
	if call {
		<-srpc.Done
	}
	return srpc
}

func (r *ServicRpc) Cb(srpc *ServiceRpcInfo) {
	defer func() {
		if r := recover(); r != nil {
			if srpc.msg.Request.Index != 0 {
				srpc.msg.Reply.Code = Error_Rpc_ExecErr.Code()
			}

			buf := make([]byte, 4096)
			l := runtime.Stack(buf, true)
			err := fmt.Errorf("%v: %s", r, buf[:l])
			log.Error("error stack:%v \n", err)
		}
		srpc.Done <- srpc
	}()

	if err := srpc.handler.Func(srpc.service, srpc.msg); err != nil {
		srpc.msg.Reply.Code = err.Code()
	}
}
